
#include <string.h>
#include "esp_system.h"
#include "mbedtls/aes.h"
#include "mbedtls/base64.h"

//#define DEFAULT_NONCE "1234567890abcdef"

static const char *TAG                       = "app aes";

// static void 
// dump(unsigned char *buf, size_t len) {
//   size_t i = 0;
//   while (i < len) {
//     printf("%02x ", buf[i++]);
//     if (i % 16 == 0)
//       printf("\n");
//   }
//   printf("\n");
// }

/*
	aes-ctr encrypt
	input
	inlen
	output  output string use base64 encode
	out_len
	
*/
int app_aes_encrypt(const char *input, size_t inlen, char **output, size_t *out_len, const char *key, const char *iv)
{
	int ret;
	mbedtls_aes_context ctx;
	size_t offset = 0;
	uint8_t nonce[16];
	uint8_t stream_block[16];
	
	uint8_t *enc_buf = calloc(inlen, 1);
	
	memcpy(nonce, iv, 16);
	//MDF_LOGD("NONCE:");
	//dump(nonce, 16);

	mbedtls_aes_init(&ctx);
	mbedtls_aes_setkey_enc(&ctx, (unsigned char *)key, 128);
	mbedtls_aes_crypt_ctr(&ctx, inlen, &offset, nonce,
						  stream_block, (const unsigned char *)input, (unsigned char *)enc_buf );
	//MDF_LOGD("AES Dec:");
	//dump(enc_buf, inlen);
	//MDF_LOGD("KEY:");
	//dump(key, 16);

	size_t out_buf_size = (inlen / 3 + (inlen % 3 != 0)) * 4 + 1;
	char * outbuf = calloc(out_buf_size, 1);
	ret = mbedtls_base64_encode((unsigned char *)outbuf, out_buf_size, out_len, (const unsigned char *)enc_buf, inlen);
	free(enc_buf);
	if(ret != 0){
		// printf("b64 encode fail %d", ret);
		free(outbuf);
		return -1;
	}
	*output = outbuf;
	// printf("B64 Eec %d:%s", *out_len, *output);
	return ret;
}

int app_aes_encrypt_bytes(const char *input, size_t inlen, char **output, size_t *out_len, const char *key, const char *iv)
{
	int ret;
	mbedtls_aes_context ctx;
	size_t offset = 0;
	uint8_t nonce[16];
	uint8_t stream_block[16];
	
	uint8_t *enc_buf = calloc(inlen, 1);
	
	memcpy(nonce, iv, 16);
	//MDF_LOGD("NONCE:");
	//dump(nonce, 16);

	mbedtls_aes_init(&ctx);
	mbedtls_aes_setkey_enc(&ctx, (unsigned char *)key, 128);
	mbedtls_aes_crypt_ctr(&ctx, inlen, &offset, nonce,
						  stream_block, (const unsigned char *)input, (unsigned char *)enc_buf );
	//MDF_LOGD("AES Dec:");
	//dump(enc_buf, inlen);
	//MDF_LOGD("KEY:");
	//dump(key, 16);
	*output = (char *)enc_buf;
	*out_len = inlen;

	return 0;
}

/*
	aes-ctr encrypt
	input input string use base64 encode
	inlen
	output  
	out_len
	
*/
int app_aes_decrypt(const char *input, size_t inlen, char **output, size_t *out_len, const char *key, const char *iv)
{
	int ret = 0;
	size_t decode_size;
	uint8_t *decode_buf = calloc(inlen, 1);
	if(0 != mbedtls_base64_decode((unsigned char *)decode_buf, inlen, &decode_size, (const unsigned char *)input, inlen)){
		// printf("mbedtls_base64_decode fail");
		free(decode_buf);
		return -1;
	}
	//MDF_LOGI("B64 Dec:");
	//dump(decode_buf, decode_size);

	mbedtls_aes_context ctx;
	size_t offset = 0;
	uint8_t nonce[16];
	uint8_t stream_block[16];
	
	memcpy(nonce, iv, 16);
	//MDF_LOGI("NONCE:");
	//dump(nonce, 16);
	//MDF_LOGI("KEY:");
	//dump(key, 16);

	char *out_buf = calloc(decode_size+1, 1);// end of 0
	
	mbedtls_aes_init(&ctx);
	mbedtls_aes_setkey_dec(&ctx, (unsigned char *)key, 128);
	mbedtls_aes_crypt_ctr(&ctx, decode_size, &offset, nonce,
				  stream_block, (const unsigned char *)decode_buf, (unsigned char *)out_buf );
	free(decode_buf);
	*out_len = decode_size;
	*output = out_buf;
	//MDF_LOGI("AES Dec %d:%s", *out_len, *output);
	return ret;
}
/*
	aes-ctr encrypt
	input input string use base64 encode
	inlen
	output  
	out_len
	
*/
int app_aes_decrypt_bytes(const char *input, size_t inlen, char **output, size_t *out_len, const char *key, const char *iv)
{
	int ret = 0;

	mbedtls_aes_context ctx;
	size_t offset = 0;
	uint8_t nonce[16];
	uint8_t stream_block[16];
	
	memcpy(nonce, iv, 16);
	//MDF_LOGI("NONCE:");
	//dump(nonce, 16);
	//MDF_LOGI("KEY:");
	//dump(key, 16);

	
	char *out_buf = calloc(inlen+1, 1);// end of 0
	
	mbedtls_aes_init(&ctx);
	mbedtls_aes_setkey_dec(&ctx, (unsigned char *)key, 128);
	mbedtls_aes_crypt_ctr(&ctx, inlen, &offset, nonce,
				  stream_block, (const unsigned char *)input, (unsigned char *)out_buf );

	*out_len = inlen;
	*output = out_buf;
	//MDF_LOGI("AES Dec %d:%s", *out_len, *output);
	return ret;
}



